#include "tapp.h"

#if defined(Q_OS_WIN32)

#ifndef IOCTL_STORAGE_QUERY_PROPERTY
#define IOCTL_STORAGE_QUERY_PROPERTY    CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif

typedef enum _STORAGE_BUS_TYPE {
    BusTypeUnknown = 0x00,
    BusTypeScsi,
    BusTypeAtapi,
    BusTypeAta,
    BusType1394,
    BusTypeSsa,
    BusTypeFibre,
    BusTypeUsb,
    BusTypeRAID,
    BusTypeMaxReserved = 0x7F
} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE;

typedef struct _STORAGE_DEVICE_DESCRIPTOR {
    ULONG  Version;
    ULONG  Size;
    UCHAR  DeviceType;
    UCHAR  DeviceTypeModifier;
    BOOLEAN  RemovableMedia;
    BOOLEAN  CommandQueueing;
    ULONG  VendorIdOffset;
    ULONG  ProductIdOffset;
    ULONG  ProductRevisionOffset;
    ULONG  SerialNumberOffset;
    STORAGE_BUS_TYPE  BusType;
    ULONG  RawPropertiesLength;
    UCHAR  RawDeviceProperties[1];
  } STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;

typedef enum _STORAGE_QUERY_TYPE {
  PropertyStandardQuery = 0,
  PropertyExistsQuery,
  PropertyMaskQuery,
  PropertyQueryMaxDefined

} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;

typedef enum _STORAGE_PROPERTY_ID {
  StorageDeviceProperty = 0,
  StorageAdapterProperty,
  StorageDeviceIdProperty

} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;

typedef struct _STORAGE_PROPERTY_QUERY {
  STORAGE_PROPERTY_ID  PropertyId;
  STORAGE_QUERY_TYPE  QueryType;
  UCHAR  AdditionalParameters[1];

} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;

BOOL GetDisksProperty(HANDLE hDevice, PSTORAGE_DEVICE_DESCRIPTOR pDevDesc)
{
    STORAGE_PROPERTY_QUERY  Query;
    DWORD   dwOutBytes;
    BOOL bResult;
    Query.PropertyId = StorageDeviceProperty;
    Query.QueryType = PropertyStandardQuery;
    bResult = DeviceIoControl(hDevice,
                              IOCTL_STORAGE_QUERY_PROPERTY,
                              &Query,
                              sizeof(STORAGE_PROPERTY_QUERY),
                              pDevDesc,
                              pDevDesc->Size,
                              &dwOutBytes,
                              (LPOVERLAPPED)NULL);
    return bResult;
}

char DriveLiterFromMask (ULONG unitmask)
{
    char i;
    for (i=0;i<26;++i) {
        if (unitmask & 0x1) {
            break;
        }
        unitmask >>= 1;
    }
    return (i + 'A');
}

#endif //Q_OS_WIN32

MyApp::MyApp(int argc, char *argv[])
    : QApplication(argc, argv)
{    
}

MyApp::~MyApp()
{

}

#if defined (Q_OS_WIN32)
bool MyApp::winEventFilter(MSG *msg, long *result)
{
    switch (msg->message)
    {
    case WM_DEVICECHANGE:
        {
            switch (msg->wParam)
            {
            case DBT_DEVICEARRIVAL: processDbtDeviceArrival(msg, result); break;
            default: break;
            }
        }
        break;
    default :
            break;
    }
    return QApplication::winEventFilter(msg, result);
}

void MyApp::processDbtDeviceArrival(MSG *msg, long *result)
{
    DEV_BROADCAST_HDR *dev = reinterpret_cast<DEV_BROADCAST_HDR*>(msg->lParam);
    switch (dev->dbch_devicetype)
    {
        case DBT_DEVTYP_VOLUME: processDevArrivalBroadcastVolume(reinterpret_cast<DEV_BROADCAST_VOLUME*>(dev), result); break;
    }
}

void MyApp::processDevArrivalBroadcastVolume(DEV_BROADCAST_VOLUME *dev, long *result)
{        
    Q_UNUSED(result);
    emit newVolumeDevice(QString(DriveLiterFromMask(dev->dbcv_unitmask)),dev->dbcv_flags);
}

#endif
